//
//  NSObject+Swizzing.m
//  teatFeng
//
//  Created by Feng on 2021/9/3.
//  Copyright © 2021 Feng. All rights reserved.
//

#import "NSObject+Swizzing.h"
#import <objc/runtime.h>

@implementation NSObject (Swizzing)
+ (void)swizzleWithSysMethod:(SEL)originalSelector swizzledMethod:(SEL)swizzledSelector {
    // Method中包含IMP函数指针，通过替换IMP，使SEL调用不同函数实现
    Method origMethod = class_getClassMethod(self, originalSelector);
    Method replaceMeathod = class_getClassMethod(self, swizzledSelector);
    Class metaKlass = objc_getMetaClass(NSStringFromClass(self).UTF8String);
    
//    class_addMethod:如果发现方法已经存在，会失败返回，也可以用来做检查用,我们这里是为了避免源方法没有实现的情况;如果方法没有存在,我们则先尝试添加被替换的方法的实现
    BOOL didAddMethod = class_addMethod(metaKlass,
                                        originalSelector,
                                        method_getImplementation(replaceMeathod),
                                        method_getTypeEncoding(replaceMeathod));
    if (didAddMethod) {
        // 原方法未实现，则替换原方法防止crash
        class_replaceMethod(metaKlass,
                            swizzledSelector,
                            method_getImplementation(origMethod),
                            method_getTypeEncoding(origMethod));
    }else {
//         添加失败：说明源方法已经有实现，直接将两个方法的实现交换即
        method_exchangeImplementations(origMethod, replaceMeathod);
    }
}

+ (void)swizzleInstanceWithSysMethod:(SEL)originalSelector swizzledMethod:(SEL)swizzledSelector {
    Method origMethod = class_getInstanceMethod(self, originalSelector);
    Method replaceMeathod = class_getInstanceMethod(self, swizzledSelector);
    
    // class_addMethod:如果发现方法已经存在，会失败返回，也可以用来做检查用,我们这里是为了避免源方法没有实现的情况;如果方法没有存在,我们则先尝试添加被替换的方法的实现
    BOOL didAddMethod = class_addMethod(self,
                                        originalSelector,
                                        method_getImplementation(replaceMeathod),
                                        method_getTypeEncoding(replaceMeathod));
    if (didAddMethod) {
        // 原方法未实现，则替换原方法防止crash
        class_replaceMethod(self,
                            swizzledSelector,
                            method_getImplementation(origMethod),
                            method_getTypeEncoding(origMethod));
    }else {
        // 添加失败：说明源方法已经有实现，直接将两个方法的实现交换即
        method_exchangeImplementations(origMethod, replaceMeathod);
    }
}

@end

